package com.dili.dd.gpi.service.impl;

import com.dili.dd.gpi.domain.GpiSnapshot;
import com.dili.dd.gpi.domain.GpiSnapshotExample;
import com.dili.dd.gpi.enums.ApplyType;
import com.dili.dd.gpi.enums.GPIType;
import com.dili.dd.gpi.enums.PrefixType;
import com.dili.dd.gpi.exception.BusinessException;
import com.dili.dd.gpi.mapper.ExtGpiSnapshotMapper;
import com.dili.dd.gpi.mapper.GpiSnapshotMapper;
import com.dili.dd.gpi.service.GpiSnapshotService;
import com.dili.dd.gpi.service.UidNameSpaceService;
import com.dili.dd.gpi.util.Pagination;
import com.dili.dd.gpi.util.StringUtils;
import com.dili.dd.gpi.util.spring.DataSourceLookupKey;
import com.dili.dd.gpi.util.spring.RequireDataSource;
import com.google.common.base.Joiner;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.MessageFormat;
import java.util.*;

/**
 * Created by zhaoYuan on 2015/3/24.
 */
@Service
public class GpiSnapshotServiceImpl implements GpiSnapshotService {

    @Resource(name = "dataBaseGenerator")
    private UidNameSpaceService uidNameSpaceService;

    @SuppressWarnings("SpringJavaAutowiringInspection")
    @Resource
    GpiSnapshotMapper gpiSnapshotMapper;

    @Resource
    ExtGpiSnapshotMapper extGpiSnapshotMapper;

    @Override
    @RequireDataSource(key = DataSourceLookupKey.GPI_DATASOURCE)
    @Transactional(readOnly = false,propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public boolean apply(Integer parentId, LinkedHashSet<String> titles,  GPIType type,String prefix,String suffix, List<String> descriptions,
                          List<GpiSnapshot> gpiSnapshots,List<GpiSnapshot> newGpis,ApplyType applyType) throws BusinessException {

        GpiSnapshot parentGpi = null;
        String parentGpiPath = null;
        String parentTitlePath = null;
        if(parentId != null){
            parentGpi = get(parentId);
            if(parentGpi == null){
                throw new BusinessException("上层gpi不存在：id=" + parentGpi);
            }
            if(!parentGpi.getType().equals(type.getParent())){
                throw new BusinessException(MessageFormat.format("上层gpi层级错误，应该是{0},实际是{1}",type,parentGpi.getType()));
            }
            parentGpiPath = parentGpi.getGpiPath();
            parentTitlePath = parentGpi.getTitlePath();
        }

        //先判断title在type下是否已经存在，就抛出异常
        List<String> titleList = new LinkedList<>(titles);
        List<GpiSnapshot> exists = isExist(titleList, type);
        Set<String> existTitles = new HashSet<>();
        if (exists != null) {
            for (GpiSnapshot gs : exists){
                gpiSnapshots.add(gs);
                existTitles.add(gs.getTitle());
            }
            titleList.removeAll(existTitles);
        }

        Date now = new Date();

        //如果不存在，则申请一个gpi
//        String gpi = uidNameSpaceService.generateUID(PrefixType.GPI, prefix,applyType);
        int generateNumber = titleList.size();
        List<String> gpis = generateGPI(PrefixType.GPI, prefix, applyType, suffix, generateNumber,"P-" + type.name());
        if(gpis != null && !gpis.isEmpty()){
            if(gpis.size() != titleList.size()) throw new BusinessException("系统错误，gpi数量和title数量不相等");
            for (int i = 0; i < titleList.size(); i++) {
                GpiSnapshot gpiSnapshot = new GpiSnapshot();
                gpiSnapshot.setType(type);
                gpiSnapshot.setParent(parentId);
                String title = titleList.get(i);
                gpiSnapshot.setTitle(title);
                gpiSnapshot.setSuffix(suffix);
                gpiSnapshot.setPrefix(prefix);
                String gpi = gpis.get(i);
                gpiSnapshot.setGpi(gpi);
                gpiSnapshot.setEventType(DEFAULT_EVENT);
                if(i < descriptions.size()){
                    gpiSnapshot.setDescribe(descriptions.get(i));
                }

                Joiner joiner = Joiner.on(".").skipNulls();
                gpiSnapshot.setGpiPath(joiner.join(parentGpiPath,gpi));
                gpiSnapshot.setTitlePath(joiner.join(parentTitlePath,title) );
                gpiSnapshot.setUpdateTime(now);
                gpiSnapshot.setCreateTime(now);
                gpiSnapshot.setDeleted(false);
                gpiSnapshotMapper.insert(gpiSnapshot);
                newGpis.add(gpiSnapshot);
            }
        }
        return true;
    }

    @Override
    @RequireDataSource(key = DataSourceLookupKey.GPI_DATASOURCE)
    @Transactional(readOnly = true,propagation = Propagation.REQUIRED)
    public List<GpiSnapshot> find(Map<String, Object> params, Pagination pagination) {
        if(pagination != null){
            params.put("pagination",pagination);
        }
        List<GpiSnapshot> gpiSnapshots = extGpiSnapshotMapper.findByParams(params);
        return gpiSnapshots;
    }

    @Override
    @RequireDataSource(key = DataSourceLookupKey.GPI_DATASOURCE)
    @Transactional(readOnly = false,propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    public List<GpiSnapshot> isExist(List<String> titles, GPIType type){
//        List<String> titles = Splitter.on(",")
//                .trimResults()
//                .omitEmptyStrings()
//                .splitToList(title);
        GpiSnapshotExample example = new GpiSnapshotExample();
        GpiSnapshotExample.Criteria criteria = example.createCriteria();
        criteria.andDeletedEqualTo(false).andTitleIn(titles).andTypeEqualTo(type);
        List<GpiSnapshot> gpiSnapshots = gpiSnapshotMapper.selectByExample(example);
        return gpiSnapshots == null || gpiSnapshots.isEmpty() ? null : gpiSnapshots;
    }

    @Override
    @RequireDataSource(key = DataSourceLookupKey.GPI_DATASOURCE)
    @Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
    public GpiSnapshot get(Integer id) {
        return gpiSnapshotMapper.selectByPrimaryKey(id);
    }

    @Override
    @RequireDataSource(key = DataSourceLookupKey.GPI_DATASOURCE)
    @Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
    public List<GpiSnapshot> subList(int id) {
        GpiSnapshotExample example = new GpiSnapshotExample();
        GpiSnapshotExample.Criteria criteria = example.createCriteria();
        criteria.andDeletedEqualTo(false).andParentEqualTo(id);
        List<GpiSnapshot> gpiSnapshots = gpiSnapshotMapper.selectByExample(example);
        return gpiSnapshots;
    }

    @Override
    @RequireDataSource(key = DataSourceLookupKey.GPI_DATASOURCE)
    @Transactional(readOnly = true,propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    public List<GpiSnapshot> findAllSystem() {
        GpiSnapshotExample example = new GpiSnapshotExample();
        GpiSnapshotExample.Criteria criteria = example.createCriteria();
        criteria.andDeletedEqualTo(false).andParentIsNull();
        List<GpiSnapshot> gpiSnapshots = gpiSnapshotMapper.selectByExample(example);
        return gpiSnapshots;
    }

    @Override
    @RequireDataSource(key = DataSourceLookupKey.GPI_DATASOURCE)
    @Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
    public List<GpiSnapshot> findByPage(String pageGpi) {
        Map<String,Object> params = new HashMap<>();
        params.put("pageGpi",pageGpi);
        params.put("type", GPIType.PAGE);
        List<GpiSnapshot> pageGpiList = extGpiSnapshotMapper.selectSubsByGpi(params);
        List<Integer> modelGpiList = new LinkedList<>();
        for (GpiSnapshot gpiSnapshot : pageGpiList) {
            modelGpiList.add(gpiSnapshot.getId());
        }

        List<GpiSnapshot> gpiSnapshots = extGpiSnapshotMapper.selectSubsByIds(modelGpiList);
        pageGpiList.addAll(gpiSnapshots);

        return pageGpiList;
    }

    @Override
    @RequireDataSource(key = DataSourceLookupKey.GPI_DATASOURCE)
    @Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
    public GpiSnapshot getByGpi(String gpi, GPIType gpiType) {
        GpiSnapshotExample example = new GpiSnapshotExample();
        GpiSnapshotExample.Criteria criteria = example.createCriteria();
        criteria.andDeletedEqualTo(false).andGpiEqualTo(gpi).andTypeEqualTo(gpiType);
        List<GpiSnapshot> gpiSnapshots = gpiSnapshotMapper.selectByExample(example);
        if(gpiSnapshots == null || gpiSnapshots.isEmpty()) return null;
        return gpiSnapshots.get(0);
    }

    private List<String> generateGPI(PrefixType type, String prefix, ApplyType applyType, String suffix, int n, String level) throws BusinessException {
        if(n < 1) return null;
        List<String> gpis = new LinkedList<>();
        for (int i = 0; i < n; i++) {
            String gpi = uidNameSpaceService.generateUID(PrefixType.GPI, prefix, applyType, level);
            if(!StringUtils.isNullOrEmpty(suffix)){
                gpi = gpi + suffix;
            }
            gpis.add(gpi);
        }
        return gpis;
    }
}
